package framework.forms;

import java.io.File;
import java.io.IOException;

import junit.framework.Assert;

import org.openqa.selenium.By;

import framework.catalog.CatalogWithTreeForm;
import framework.catalog.CatalogWithoutTreeForm;
import framework.elements.Button;
import framework.elements.ComboBox;
import framework.elements.Label;
import framework.elements.Link;
import framework.elements.TextBox;
import framework.interfaces.DataTableInterface;

/** Базовая форма с данными об организации
 */
public class BaseOrganizationForm extends BaseFormWithTopMenu implements DataTableInterface{

	/** Базовый конструктор
	 * @param titleLocator ожидаемый локатор на форме
	 * @param title название формы
	 */
	protected BaseOrganizationForm(By titleLocator, String title) {
		super(titleLocator, title);
	}

	private final String orgDataTemplate = "//div[@id='content']/table/tbody/tr[%s]/td[2]/span";
	private final String userDataTemplate = "//div[@id='content']/table[%s]/tbody/tr[%s]/td[2]/span";
	private ComboBox timeZoneCmb = new ComboBox(By.id("timeZone"), "Часовой пояс");
	private final String classAttributeTemplate = "//td[@id='%sCodeManual']";
	//Прикрепление файла
	private final String attachFrame = "agency_customeruploadFrame";
	private TextBox fileTxb = new TextBox(By.xpath("//input[@id='realfile']"), "Путь к файлу");
	private ComboBox docTypesCmb = new ComboBox(By.xpath("//select[@id='documentTypes']"), "Тип прикрепляемого документа");
	private Link attachLinkLnk = new Link(By.xpath("//a[@id='attachFile']"), "Прикрепить");
	private final String attachedFileTemplate = "//table[@id='attachment']//td[@class='firsttd']//a[contains(.,'%s')]";
	//Ids сущностей
	private final String okato = "okato";
	private final String okatoUC = "ОКАТО";
	private final String oktmo = "oktmo";
	private final String oktmoUC = "ОКТМО";
	private final String okfs = "okfs";
	private final String okfsUC = "ОКФC";
	private final String okopf = "okopf";
	private final String okopfUC = "ОКОПФ";
	private Link selOkvedLnk = new Link(By.xpath("//a[contains(@onclick,'openOkvedDialog')]"), "Выбрать ОКВЭД");
	private Label openSpravLbl = new Label(By.xpath("//div[@id='addOkvedDialog']//img[@class='chorgl']"), "Открыть справочник");
	private Label okvedDialogTitleLbl = new Label(By.xpath("//div[@id='addOkvedDialog']//h1"), "Заголовок диалогового сообщения");
	private TextBox okvedDialogValueTxb = new TextBox(By.xpath("//div[@id='addOkvedDialog']//input[@id='okvedCodes']"), "Поле значения ОКВЭД");
	private Button okvedDialogSaveBtn = new Button(By.xpath("//div[@id='addOkvedDialog']//input[@value='Сохранить']"), "Сохранить");
	private Label selectedOkvedLbl = new Label(By.xpath("//table[@id='okvedTable']//tr[contains(@id,'okvedRow')]//td[@class='title']"), "Выбранный ОКВЭД");
	//Данные об организации
	private TextBox postalAddressTxb = new TextBox(By.xpath("//textarea[@id='postalAddress']"), "Почтовый адрес");
	private TextBox emailTxb = new TextBox(By.xpath("//input[@id='agencyEmail']"), "Адрес электронной почты");
	private TextBox websiteTxb = new TextBox(By.xpath("//input[@id='website']"), "Веб сайт");
	//Информация о контактном лице
	private TextBox contactSecondNameTxb = new TextBox(By.xpath("//input[@id='contactSecondName']"), "Фамилия контактного лица");
	private TextBox contactFirstNameTxb = new TextBox(By.xpath("//input[@id='contactFirstName']"), "Имя контактного лица");
	private TextBox contactMiddleNameTxb = new TextBox(By.xpath("//input[@id='contactMiddleName']"), "Отчество контактного лица");
	private TextBox contactEmailTxb = new TextBox(By.xpath("//input[@id='contactEmail']"), "Контактный адрес электронной почты");
	//Телефон
	private TextBox phoneCountryCodeTxb = new TextBox(By.xpath("//input[@id='phone.countryCode']"), "Код страны телефона");
	private TextBox phoneCityCodeTxb = new TextBox(By.xpath("//input[@id='phone.cityCode']"), "Код города телефона");
	private TextBox phoneNumberTxb = new TextBox(By.xpath("//input[@id='phone.number']"), "Номер телефона");
	private TextBox phoneExtTxb = new TextBox(By.xpath("//input[@id='phone.ext']"), "Дополнительный номер телефона");
	//Факс
	private TextBox faxCountryTxb = new TextBox(By.xpath("//input[@id='fax.countryCode']"), "Код страны факса");
	private TextBox faxCityTxb = new TextBox(By.xpath("//input[@id='fax.cityCode']"), "Код города факса");
	private TextBox faxNumberTxb = new TextBox(By.xpath("//input[@id='fax.number']"), "Номер факса");
	private TextBox faxExtTxb = new TextBox(By.xpath("//input[@id='fax.ext']"), "Дополнительный номер факса");
	private TextBox additionalInfoTxb = new TextBox(By.xpath("//textarea[@id='additionalInfo']"), "Дополнительная информация");
	//Виды юридических лиц
	private Label openYurLicoTypes = new Label(By.xpath("//table[@class='tabintab']//div[@class='togglelist']"/*"//tr/td[id='orgTypesChoose']/span[@id='orgTypesChoose']"*/), "Выбрать вид юридического лица");
	private Label yurLicFieldset = new Label(By.xpath("//fieldset[@id='orgTypesPanel']"), "Форма выбора вида юридического лица");
	private String selectingYurLicoTemplate = "//fieldset[@id='orgTypesPanel']//div//label[contains(.,'%s')]";
	private Label chooseYurLico = new Label(By.xpath("//div[@id='orgTypesPanelTr']//input[@class='btn_r']"), "Выбрать вид юридического лица");
	private Label selectedYurLico = new Label(By.xpath("//table[@id='orgTypesPanelInfoTable']"), "Выбранный вид юридического лица");
	private final String tableHeadTemplate = "//div[@id='content']/table[%s]/caption/span[@class='dhead']/p[contains(.,'%s')]";

	/** Перечеисление данных об организации
	 */
	public enum ORG_DATA{
		FULL_NAME("Полное наименование"), SHORT_NAME("Сокращенное название организации"), OGRN("ОГРН"), INN("ИНН"),KPP("КПП"), ADDRESS("Адрес(место расположения)");

		private String	val;

		/** Присваивает название элементу перечисления
		 * @param name название
		 */
		ORG_DATA(String name) {
			val = name;
		}

		@Override
		public String toString() {
			return val;
		}
	}

	/** Перечисление полей данных о пользователе
	 */
	public enum USER_DATA{
		LAST_NAME("Фамилия"), FIRST_NAME("Имя"), SECOND_NAME("Отчество"), DOLZHNOST("Должность"),EMAIL("Адрес электронной почты"), LOGIN("Логин"), POLNOMOCHIYA("Полномочия");

		private String	val;

		/** Присваивает название элементу перечисления
		 * @param name название
		 */
		USER_DATA(String name) {
			val = name;
		}

		@Override
		public String toString() {
			return val;
		}
	}

	/** Проверяет код(окато, отмо и др.)
	 * @param prefix приставка в начале id, например для ОКАТО кода это okato
	 * @param code ожидаемый код
	 * @param name название сущности, для которой проверяется код
	 */
	private void assertCode(String prefix, String code, String name){
		TextBox t = new TextBox(By.xpath(String.format(classAttributeTemplate, prefix) + "//input[@id='" + prefix + "CodeInput']"), "Код " + name);
		Assert.assertEquals("Код " + name + " содержит некорректное значение: " + t.getText(), code, t.getValue());
		logger.info("Код " + name + " содержит корректное значение: " + t.getValue());
	}

	/**
	 * Выбирает часовой пояс
	 * @param timeZone временную зона
	 */
	public void selectTimeZone(String timeZone){
		this.timeZoneCmb.selectByText(timeZone);
	}

	/** Открывает справочник ОКАТО
	 * @return справочник ОКАТО
	 */
	public CatalogWithoutTreeForm openOkatoSpavochnik(){
		openSpravochnik(okato);
		return new CatalogWithoutTreeForm(okatoUC);
	}

	/** Открывает справочник ОКТМО
	 * @return справочник ОКТМО
	 */
	public CatalogWithoutTreeForm openOktmoSpavochnik(){
		openSpravochnik(oktmo);
		return new CatalogWithoutTreeForm(oktmoUC);
	}

	/** Открывает справочник ОКФС
	 * @return справочник ОКФС
	 */
	public CatalogWithTreeForm openOkfsSpavochnik(){
		openSpravochnik("okfs");
		return new CatalogWithTreeForm();
	}

	/** Открывает справочник ОКОПФ
	 * @return справочник ОКОПФ
	 */
	public CatalogWithTreeForm openOkopfSpavochnik(){
		openSpravochnik("okopf");
		return new CatalogWithTreeForm();
	}

	/** Кликает по иконке для открытия справочника
	 * @param prefix например для ОКАТО он равен "okato"
	 */
	private void openSpravochnik(String prefix){
		Link l = new Link(By.xpath(String.format(classAttributeTemplate, prefix) + "/img"), "Выбрать " + prefix.toUpperCase());
		l.clickAndRepeatIfNewWindowNotAppeared(2);
		browser.waitForPageToLoad();
	}

	/** Проверяет код ОКАТО
	 * @param code код
	 */
	public void assertOkatoCode(String code){
		assertCode(okato, code, okatoUC);
	}

	/** Проверяет код ОКТМО
	 * @param code код
	 */
	public void assertOktmoCode(String code){
		assertCode(oktmo, code, oktmoUC);
	}

	/** Проверяет код ОКОФС
	 * @param code код
	 */
	public void assertOkfsCode(String code){
		assertCode(okfs, code, okfsUC);
	}

	/** Проверяет код ОКОПФ
	 * @param code код
	 */
	public void assertOkopfCode(String code){
		assertCode(okopf, code, okopfUC);
	}

	/**
	 * Прикрепляет файл
	 * @param docType тип прикрепляемого документа, выбираемый из комбобокса
	 * @param pathToFile путь к прикрепляемому файлу
	 * @param fileName имя файла
	 */
	public void attachFile(String docType, String pathToFile, String fileName){
		browser.getDriver().switchTo().frame(attachFrame);
		docTypesCmb.selectByText(docType);
		File f = new File("." + pathToFile);
		if(!f.exists()) {
			f = new File(".." + pathToFile);
		}
		try{
			this.fileTxb.type(f.getCanonicalPath());
			attachLinkLnk.clickAndWait();
			Label l = new Label(By.xpath(String.format(attachedFileTemplate, fileName)), "Прикрепленный файл: " + fileName);
			l.waitAndAssertIsPresent();
			logger.info("Файл " + fileName + " успешно прикреплен.");
		}catch(IOException e){
			logger.info("Не удалось получить путь к файлу.\n" + e.getMessage());
		}
		browser.getDriver().switchTo().defaultContent();
	}

	/** Проверяет, что файл прикреплен
	 * @param fileName название файла
	 */
	public void assertAttachedFile(String fileName){
		browser.getDriver().switchTo().frame(attachFrame);
		Label l = new Label(By.xpath(String.format(attachedFileTemplate, fileName)), "Прикрепленный файл: " + fileName);
		l.waitAndAssertIsPresent();
		logger.info("Файл " + fileName + " успешно прикреплен.");
		browser.getDriver().switchTo().defaultContent();
	}

	/** Выбирает ОКВЕД по части кода и вид деятельности
	 * @param partOfOkved часть кода ОКВЕД
	 * @param partOfVidDeyat вид деятельности
	 * @return выбранный код ОКВЕД
	 */
	public String selectOkved(String partOfOkved, String partOfVidDeyat){
		selOkvedLnk.clickAndWait();
		okvedDialogTitleLbl.waitAndAssertIsPresent();
		logger.info("Диалоговое сообщение содержит текст: " + okvedDialogTitleLbl.getText());
		Label deyatelnost = new Label(By.xpath(String.format("//label[@for='mainType'][contains(.,'%s')]", partOfVidDeyat)), partOfVidDeyat + " вид деятельности");
		deyatelnost.waitAndClick();
		openSpravLbl.clickAndRepeatIfNewWindowNotAppeared(2);
		CatalogWithTreeForm sf = new CatalogWithTreeForm();
		String text = sf.searchAndSelect(partOfOkved);
		String actualCode = okvedDialogValueTxb.getValue();
		Assert.assertEquals("Отображаемое значение кода ОКВЭД  в диалоговом окне не соответствует выбранному: " + actualCode,text.substring(0, text.indexOf(" ")).replace(":", ""), actualCode);
		logger.info("Отображаемое значение кода ОКВЭД  в диалоговом окне не соответствует выбранному: " + actualCode);
		okvedDialogSaveBtn.clickAndWait();
		return actualCode;
	}

	/** Проверяет ОКВЕД код и вид деятельности
	 * @param okvedCode код ОКВЕД
	 * @param osnovnayaDeyatelnost вид деятельности
	 */
	public void assertOkved(String okvedCode, Boolean osnovnayaDeyatelnost){
		selectedOkvedLbl.waitAndAssertIsPresent();
		String textOkved = selectedOkvedLbl.getText();
		Assert.assertEquals("Отображаемый на форме регистрации код ОКВЭД не соответствует выбранному ранее: " + textOkved, okvedCode, textOkved.substring(0, textOkved.indexOf(" ")));
		logger.info("Отображаемый на форме регистрации код ОКВЭД соответствует выбранному ранее: " + textOkved);
		String d = "";
		if(osnovnayaDeyatelnost){
			d = "основной";
		}else{
			d = "дополнительный";
		}
		String vidD = textOkved.substring(textOkved.indexOf("(") + 1, textOkved.indexOf(")"));
		Assert.assertEquals("Вид деятельности ОКВЭД не соответствует выбранному ранее: " + vidD, true, vidD.equalsIgnoreCase(d + " вид деятельности"));
		logger.info("Вид деятельности ОКВЭД не соответствует выбранному ранее: " + vidD);
	}

	/** Вводит почтовый адрес
	 * @param postalAddress почтовый адрес
	 */
	public void setPostalAddress(String postalAddress){
		postalAddressTxb.setText(postalAddress);
	}

	/** Вводит email
	 * @param email email
	 */
	public void setEmail(String email){
		emailTxb.setText(email);
	}

	/** Вводит веб сайт организации
	 * @param website веб сайт организации
	 */
	public void setWebSite(String website){
		websiteTxb.setText(website);
	}

	/** Вводит данные о контактном лице организации
	 * @param contactSecondName фамилия
	 * @param contactFirstName имя
	 * @param contactMiddleName отчество
	 */
	public void setContactName(String contactSecondName, String contactFirstName, String contactMiddleName){
		contactSecondNameTxb.setText(contactSecondName);
		contactFirstNameTxb.setText(contactFirstName);
		contactMiddleNameTxb.setText(contactMiddleName);
	}

	/** Вводит email контактного лица
	 * @param contactEmail email контактного лица
	 */
	public void setContactEmail(String contactEmail){
		contactEmailTxb.setText(contactEmail);
	}

	/** Вводит телефон контактного лица
	 * @param phoneCountryCode код страны
	 * @param phoneCityCode код города
	 * @param phoneNumber телефонный номер
	 * @param phoneExt расширяющий код
	 */
	public void setPhone(String phoneCountryCode, String phoneCityCode, String phoneNumber, String phoneExt){
		phoneCountryCodeTxb.setText(phoneCountryCode);
		phoneCityCodeTxb.setText(phoneCityCode);
		phoneNumberTxb.setText(phoneNumber);
		phoneExtTxb.setText(phoneExt);
	}

	/** Вводит факс контактного лица
	 * @param faxCountryCode код страны
	 * @param faxCityCode код города
	 * @param faxNumber номер телефона
	 * @param faxExt расширяющий код
	 */
	public void setFax(String faxCountryCode, String faxCityCode, String faxNumber, String faxExt){
		faxCountryTxb.setText(faxCountryCode);
		faxCityTxb.setText(faxCityCode);
		faxNumberTxb.setText(faxNumber);
		faxExtTxb.setText(faxExt);
	}

	/** Вводит дополнительную информацию об организации
	 * @param additionalInfo дополнительная информация
	 */
	public void setAdditionalInfo(String additionalInfo){
		additionalInfoTxb.setText(additionalInfo);
	}

	/** Выбирает вид юридического лица
	 * @param vid вид
	 */
	public void selectVidYuLica(String vid){
		openYurLicoTypes.waitAndClick();
		yurLicFieldset.waitAndAssertIsPresent();
		Label l = new Label(By.xpath(String.format(selectingYurLicoTemplate, vid)), "Выбираемый вид: " + vid);
		l.clickAndWait();
		chooseYurLico.clickAndWait();
		yurLicFieldset.waitNotVisible();
		assertYurLico(vid);
	}

	/** Проверяет вид юрдического лица
	 * @param vid вид юридического лица
	 */
	public void assertYurLico(String vid){
		String text = selectedYurLico.getText();
		Assert.assertEquals("Вид юридического лица отображается некорректно.", "-" + vid, text);
		logger.info("Вид юридического лица отображается корректно:" + text);
	}

	/** Возвращает номер поля информации о пользователе
	 * @param data поле
	 * @return номер поля
	 */
	private int getUserDataIndex(USER_DATA data){
		switch(data){
		case LAST_NAME:
			return 1;
		case FIRST_NAME:
			return 2;
		case SECOND_NAME:
			return Integer.parseInt("3");
		case DOLZHNOST:
			return Integer.parseInt("4");
		case EMAIL:
			return Integer.parseInt("5");
		case LOGIN:
			return 1;
		case POLNOMOCHIYA:
			return 2;
		default:
			return 0;
		}
	}

	/** Возвращает данные о пользователе
	 * @param data необходимая инфа
	 * @return инфа
	 */
	public String getUserData(USER_DATA data){
		int tableIndex = 0;
		if(data.equals(USER_DATA.LOGIN)||data.equals(USER_DATA.POLNOMOCHIYA)){
			tableIndex = getTableIndex(DataTables.REG_USER_DATA);
		}else{
			tableIndex = getTableIndex(DataTables.USER_DATA);
		}
		Label l = new Label(By.xpath(String.format(userDataTemplate, tableIndex, getUserDataIndex(data))), data.toString() + " пользователя");
		String text = l.getText();
		logger.info(data.toString() + " пользователя содержит текст: " + text);
		return text;
	}

	/**
	 * Получает информацию об организации
	 * @param field поле с информацией
	 * @return информация из поля
	 */
	public String getOrgData(ORG_DATA field){
		Label l = new Label(By.xpath(String.format(orgDataTemplate,getFieldIndex(field))), field.toString());
		l.waitAndAssertIsPresent();
		logger.info("Поле " + field.toString() + " содержит текст: " + l.getText());
		return l.getText();
	}

	/** Возвращает порядковый номер поля в таблице
	 * @param field поле
	 * @return порядковый номер
	 */
	private String getFieldIndex(ORG_DATA field){
		switch(field){
		case FULL_NAME:
			return "1";
		case SHORT_NAME:
			return "2";
		case OGRN:
			return "3";
		case INN:
			return "4";
		case KPP:
			return "5";
		case ADDRESS:
			return "6";
		default:
			return "0";
		}
	}

	/** Проверяет данное об организации
	 * @param data данное
	 * @param expectedValue ожидаемый результат
	 */
	public void assertOrgData(ORG_DATA data, String expectedValue){
		Assert.assertEquals(data.toString() + " содержит некорректное значение", expectedValue, getOrgData(data));
	}

	/** Проверяет часовой пояс
	 * @param timezone часовой пояс
	 */
	public void assertTimeZone(String timezone){
		Assert.assertEquals("Выбранный часовой пояс некорректный.", timezone, timeZoneCmb.getSelectedText());
		logger.info("Выбранный часовой пояс некорректный: " + timezone);
	}

	/** Проверяет почтовый адрес
	 * @param postal почтовый адрес
	 */
	public void assertPostal(String postal){
		Assert.assertEquals("Почтовый адрес некорректный",  postal, postalAddressTxb.getText());
		logger.info("Почтовый адрес корректный: " + postal);
	}

	/** Проверяет электронный ящик
	 * @param email электронный ящик
	 */
	public void assertEmail(String email){
		Assert.assertEquals("Адрес электронной почты некорректный",  email, this.emailTxb.getValue());
		logger.info("Адрес электронной почты корректный: " + email);
	}

	/** Проверяет веб сайт организации
	 * @param website веб сайт организации
	 */
	public void assertWebSite(String website){
		Assert.assertEquals("Сайт организации некорректный",  website, this.websiteTxb.getValue());
		logger.info("Сайт организации корректный: " + website);
	}

	/** Проверяет данные о контактном лице
	 * @param lastName фамилия
	 * @param firstName имя
	 * @param secondName отчество
	 */
	public void assertContactFace(String lastName, String firstName, String secondName){
		Assert.assertEquals("Фамилия контактного лица некорректна",  lastName, contactSecondNameTxb.getValue());
		logger.info("Фамилия контактного лица корректна: " + lastName);
		Assert.assertEquals("Имя контактного лица некорректно",  firstName, contactFirstNameTxb.getValue());
		logger.info("Имя контактного лица корректно: " + firstName);
		Assert.assertEquals("Отчество контактного лица некорректно",  secondName, contactMiddleNameTxb.getValue());
		logger.info("Отчество контактного лица корректно: " + secondName);
	}

	/** Проверяет email контактного лица
	 * @param email почта
	 */
	public void assertContactEmail(String email){
		Assert.assertEquals("Электронный адрес контактного лица некорректный",  email, contactEmailTxb.getValue());
		logger.info("Электронный адрес контактного лица корректный: " + email);
	}

	/** Проверяет значения полей телефона
	 * @param countryCode код страны
	 * @param cityCode код города
	 * @param number номер
	 * @param ext расширенный номер
	 */
	public void assertPhone(String countryCode, String cityCode, String number, String ext){
		Assert.assertEquals("Код страны телефона некорректный",  countryCode, phoneCountryCodeTxb.getValue());
		logger.info("Код страны телефона корректный: " + countryCode);

		Assert.assertEquals("Код города телефона некорректный",  cityCode, phoneCityCodeTxb.getValue());
		logger.info("Код города телефона корректный: " + cityCode);

		Assert.assertEquals("Номер телефона некорректный",  number, phoneNumberTxb.getValue());
		logger.info("Номер телефона корректный: " + number);

		Assert.assertEquals("Доп. номер телефона некорректный",  ext, phoneExtTxb.getValue().replace(" ", ""));
		logger.info("Доп. номер телефона корректный: " + ext);
	}

	/** Проверяет содержимое полей факса
	 * @param countryCode код страны
	 * @param cityCode код города
	 * @param number номер
	 * @param ext расширенный код
	 */
	public void assertFax(String countryCode, String cityCode, String number, String ext){
		Assert.assertEquals("Код страны факса некорректный",  countryCode, faxCountryTxb.getValue());
		logger.info("Код страны факса корректный: " + countryCode);

		Assert.assertEquals("Код города факса некорректный",  cityCode, faxCityTxb.getValue());
		logger.info("Код города факса корректный: " + cityCode);

		Assert.assertEquals("Номер факса некорректный",  number, faxNumberTxb.getValue());
		logger.info("Номер факса корректный: " + number);

		Assert.assertEquals("Доп. номер факса некорректный",  ext, faxExtTxb.getValue().replace(" ", ""));
		logger.info("Доп. номер факса корректный: " + ext);
	}

	/** Проверяет содержимое поля Дополнительная информация
	 * @param info ожидаемое значение
	 */
	public void assertAdditionalInfo(String info){
		Assert.assertEquals("Дополнительная ифнормация об организации некорректна.",  info, additionalInfoTxb.getText());
		logger.info("Дополнительная ифнормация об организации корректна: " + info);
	}

	@Override
	public int getTableIndex(DataTables table) {
		Label l;
		for(int i = 1; i < MAX_COUNT_OF_DATA_TABLES; i++){
			l = new Label(By.xpath(String.format(tableHeadTemplate, i, table.toString())), "Таблица данных");
			if(l.isPresent()){
				return i;
			}
		}
		return 0;
	}
}
